home *** CD-ROM | disk | FTP | other *** search
/ Otherware / Otherware_1_SB_Development.iso / mac / developm / source / rclesrc.10 / TCP Libraries / TCPConnections.unit next >
Encoding:
Text File  |  1992-08-13  |  16.8 KB  |  620 lines

  1. unit TCPConnections;
  2.  
  3. { This program was written by Peter N Lewis, Mar 1992 in THINK Pascal 4.0.1 }
  4.  
  5. interface
  6.  
  7. uses
  8.     TCPTypes, TCPStuff;
  9.  
  10. const  { Tuning parameters }
  11.     max_connections = 20;
  12.     tooManyConnections = -23099;
  13.     TO_FindAddress = 40 * 60;
  14.     TO_FindName = 40 * 60;
  15.     TO_ActiveOpen = 20 * 60;
  16.     TO_Closing = 20 * 60;
  17.     TO_PassiveOpen = longInt(10) * 365 * 24 * 3600 * 60;  { Ten years should be safe enough right? :-) }
  18.  
  19. const
  20.     any_connection = 0;    { Pass to GetConnectionEvent }
  21.     no_connection = -1;    { Guaranteed invalid connection }
  22.  
  23. type
  24.     connectionIndex = longInt;
  25.     connectionEvent = (C_NoEvent, C_Found, C_SearchFailed, C_NameFound, C_NameSearchFailed,{}
  26.         C_Established, C_FailedToOpen, C_Closing, C_Closed, C_CharsAvailable, C_HeartBeat);
  27.     connectionEventRecord = record
  28.             event: connectionEvent;
  29.             connection: connectionIndex;
  30.             tcpc: TCPConnectionPtr;
  31.             dataptr: ptr;
  32.             value: longInt;
  33.             timedout: boolean;
  34.         end;
  35.  
  36. function InitConnections (hostFile: str255): OSErr;
  37. procedure CloseConnections;
  38. procedure TerminateConnections;
  39. function CanQuit: boolean;
  40. { After Terminate, keep calling GetConnectionEvent(any_connection,cer) until CanQuit is true, then Finish }
  41. procedure FinishConnections;
  42. procedure FinishEverything;  { Or just call FinishEverything }
  43. function ValidConnection (var cp: connectionIndex): boolean; { added for external use by ot }
  44. function FindAddress (var cp: connectionIndex; hostName: str255; dataptr: univ ptr): OSErr;
  45. function FindName (var cp: connectionIndex; hostIP: longInt; dataptr: univ ptr): OSErr;
  46. procedure FindString (hostIP: longInt; var s: str255);
  47. function NewPassiveConnection (var cp: connectionIndex; buffersize: longInt; localport: integer; remotehost: longInt; remoteport: integer; dataptr: univ ptr): OSErr;
  48. function NewActiveConnection (var cp: connectionIndex; buffersize: longInt; remotehost: longInt; remoteport: integer; dataptr: univ ptr): OSErr;
  49. procedure CloseConnection (cp: connectionIndex);
  50. procedure AbortConnection (cp: connectionIndex); { Violently close connection }
  51. function GetConnectionEvent (cp: connectionIndex; var cer: connectionEventRecord): boolean;
  52. { Pass any_connection for any event, otherwise cp specifies the event }
  53. procedure SetDataPtr (cp: connectionIndex; dataptr: univ ptr);
  54. procedure GetDataPtr (cp: connectionIndex; var dataptr: univ ptr);
  55. procedure SetConnectionTimeout (cp: connectionIndex; timeout: longInt);
  56. procedure GetConnectionTimeout (cp: connectionIndex; var timeout: longInt);
  57. procedure GetConnectionTCPC (cp: connectionIndex; var tcpc: TCPConnectionPtr);
  58. procedure SetHeartBeat (cp: connectionIndex; n: longInt); { Send C_HeartBeat every n ticks, 0 disables heartbeat }
  59.  
  60. implementation
  61.  
  62. const
  63.     TCPCMagic = 'TCPC';
  64.     TCPCBadMagic = 'badc';
  65.  
  66. type
  67.     myHostInfo = record
  68.             hi: hostInfo;
  69.             done: signedByte;
  70.         end;
  71.     myHostInfoPtr = ^myHostInfo;
  72.     statusType = (CS_None, CS_Searching, CS_NameSearching, CS_Opening, CS_Established, CS_Closing);
  73.     connectionRecord = record
  74.             magic: OSType;
  75.             conmagic: longInt;
  76.             tcpc: TCPConnectionPtr;
  77.             status: statusType;
  78.             cacheFaultReturnP: myHostInfoPtr;
  79.             closedone: boolean;
  80.             timeout: longInt;
  81.             dataptr: ptr;
  82.             heartbeat: longInt; { Time for next heartbeat }
  83.             period: longInt; { Ticks per heartbeat }
  84.         end;
  85.  
  86. var
  87.     connections: array[1..max_connections] of connectionRecord;
  88.     connectionItem: connectionIndex;
  89.     dnrptr: ptr;
  90.     connectionmagic: longInt;
  91.  
  92. function ValidConnection (var cp: connectionIndex): boolean;
  93.     var
  94.         ocp: longInt;
  95.         vc: boolean;
  96.     begin
  97.         vc := false;
  98.         ocp := cp;
  99.         cp := cp mod (max_connections + 1);
  100.         if cp > 0 then
  101.             if connections[cp].magic = TCPCMagic then
  102.                 if connections[cp].conmagic = ocp then
  103.                     vc := true;
  104.         if not vc then
  105.             DebugStr('Invalid Connection');
  106.         ValidConnection := vc;
  107.     end;
  108.  
  109. procedure SetDataPtr (cp: connectionIndex; dataptr: univ ptr);
  110.     begin
  111.         if ValidConnection(cp) then
  112.             connections[cp].dataptr := dataptr;
  113.     end;
  114.  
  115. procedure GetDataPtr (cp: connectionIndex; var dataptr: univ ptr);
  116.     begin
  117.         if ValidConnection(cp) then
  118.             dataptr := connections[cp].dataptr
  119.         else
  120.             dataptr := nil;
  121.     end;
  122.  
  123. procedure SetConnectionTimeout (cp: connectionIndex; timeout: longInt);
  124.     begin
  125.         if ValidConnection(cp) then
  126.             connections[cp].timeout := timeout;
  127.     end;
  128.  
  129. procedure GetConnectionTimeout (cp: connectionIndex; var timeout: longInt);
  130.     begin
  131.         if ValidConnection(cp) then
  132.             timeout := connections[cp].timeout
  133.         else
  134.             timeout := -1;
  135.     end;
  136.  
  137. procedure SetHeartBeat (cp: connectionIndex; n: longInt); { Send C_HeartBeat every n ticks }
  138.     begin
  139.         if ValidConnection(cp) then begin
  140.             if (n < 1) or (n = maxLongInt) then begin
  141.                 connections[cp].period := maxLongInt;
  142.                 connections[cp].heartbeat := maxLongInt;
  143.             end
  144.             else begin
  145.                 connections[cp].period := n;
  146.                 connections[cp].heartbeat := TickCount + n;
  147.             end;
  148.         end;
  149.     end;
  150.  
  151. procedure GetConnectionTCPC (cp: connectionIndex; var tcpc: TCPConnectionPtr);
  152.     begin
  153.         if ValidConnection(cp) then
  154.             tcpc := connections[cp].tcpc
  155.         else
  156.             tcpc := nil;
  157.     end;
  158.  
  159. function MyTCPState (con: TCPConnectionPtr): TCPStateType;
  160.     begin
  161.         if con = nil then
  162.             MyTCPState := T_Closed
  163.         else
  164.             MyTCPState := TCPState(con);
  165.     end;
  166.  
  167. {$S Init}
  168. function InitConnections (hostFile: str255): OSErr;
  169.     var
  170.         oe, ooe: OSErr;
  171.         i: connectionIndex;
  172.     begin
  173.         for i := 1 to max_connections do
  174.             connections[i].magic := TCPCBadMagic;
  175.         connectionmagic := 0;
  176.         connectionItem := 1;
  177.         oe := TCPInit;
  178.         if oe = noErr then begin
  179.             oe := TCPOpenResolver(hostFile, dnrptr);
  180.             if oe <> noErr then
  181.                 TCPFinish;
  182.         end;
  183.         InitConnections := oe;
  184.     end;
  185.  
  186. {$S Term}
  187. procedure TerminateConnections;
  188.     var
  189.         i: connectionIndex;
  190.         oe: OSErr;
  191.     begin
  192.         for i := 1 to max_connections do
  193.             with connections[i] do
  194.                 if magic = TCPCMagic then
  195.                     if (status = CS_Established) or (status = CS_Opening) or (status = CS_Closing) then
  196.                         if TCPState(tcpc) <> T_Closed then
  197.                             oe := TCPAbort(tcpc);
  198.     end;
  199.  
  200. {$S Term}
  201. procedure CloseConnections;
  202.     var
  203.         i: connectionIndex;
  204.         oe: OSErr;
  205.     begin
  206.         for i := 1 to max_connections do
  207.             with connections[i] do
  208.                 if magic = TCPCMagic then
  209.                     if (status = CS_Established) or (status = CS_Opening) or (status = CS_Closing) then
  210.                         if TCPState(tcpc) <> T_Closed then
  211.                             oe := TCPClose(tcpc, nil);
  212.     end;
  213.  
  214. {$S Term}
  215. function CanQuit: boolean;
  216.     var
  217.         i: connectionIndex;
  218.     begin
  219.         CanQuit := true;
  220.         for i := 1 to max_connections do
  221.             if connections[i].magic = TCPCMagic then
  222.                 CanQuit := false;
  223.     end;
  224.  
  225. {$S Term}
  226. procedure FinishConnections;
  227.     begin
  228.         TCPCloseResolver(dnrptr);
  229.         TCPFinish;
  230.     end;
  231.  
  232. {$S Term}
  233. procedure FinishEverything;
  234.     var
  235.         cer: connectionEventRecord;
  236.         dummy: boolean;
  237.         er: eventrecord;
  238.         oe: OSErr;
  239.     begin
  240.         TerminateConnections;
  241.         while not CanQuit do begin
  242.             if GetConnectionEvent(any_connection, cer) then begin
  243.                 dummy := WaitNextEvent(everyEvent, er, 0, nil);
  244.             end
  245.             else
  246.                 dummy := WaitNextEvent(everyEvent, er, 5, nil);
  247.         end;
  248.         FinishConnections;
  249.     end;
  250.  
  251. {$S}
  252. function CreateConnection (var cp: connectionIndex; dp: ptr): OSErr;
  253.     begin
  254.         connectionmagic := connectionmagic + max_connections + 1;
  255.         cp := 1;
  256.         while (connections[cp].magic = TCPCMagic) and (cp < max_connections) do
  257.             cp := cp + 1;
  258.         with connections[cp] do begin
  259.             if magic = TCPCMagic then
  260.                 CreateConnection := tooManyConnections
  261.             else begin
  262.                 magic := TCPCMagic;
  263.                 conmagic := cp + connectionmagic;
  264.                 closedone := false;
  265.                 tcpc := nil;
  266.                 status := CS_None;
  267.                 cacheFaultReturnP := nil;
  268.                 timeout := maxlongInt;
  269.                 dataptr := dp;
  270.                 period := maxLongInt;
  271.                 heartbeat := maxLongInt;
  272.                 CreateConnection := noErr;
  273.                 cp := cp + connectionmagic;
  274.             end;
  275.         end;
  276.     end;
  277.  
  278. procedure DestroyConnection (var cp: connectionIndex);
  279.     begin
  280.         if not ValidConnection(cp) then
  281.             DebugStr('Destroy Connection failed')
  282.         else
  283.             connections[cp].magic := TCPCBadMagic;
  284.         cp := -1;
  285.     end;
  286.  
  287. function FindAddress (var cp: connectionIndex; hostName: str255; dataptr: univ ptr): OSErr;
  288.     var
  289.         oe: OSErr;
  290.         cpi: connectionIndex;
  291.     begin
  292.         oe := CreateConnection(cp, dataptr);
  293.         if oe = noErr then begin
  294.             cpi := cp;
  295.             if ValidConnection(cpi) then begin
  296.                 with connections[cpi] do begin
  297.                     cacheFaultReturnP := myHostInfoPtr(NewPtr(SizeOf(myHostInfo)));
  298.                     if cacheFaultReturnP = nil then
  299.                         oe := memFullErr
  300.                     else begin
  301.                         cacheFaultReturnP^.done := 0;
  302.                         oe := TCPStrToAddr(dnrptr, hostName, cacheFaultReturnP^.hi, cacheFaultReturnP^.done);
  303.                         if oe = cacheFault then begin
  304.                             timeout := TickCount + TO_FindAddress;
  305.                             oe := noErr;
  306.                         end
  307.                         else begin
  308.                             cacheFaultReturnP^.done := -1;
  309.                             cacheFaultReturnP^.hi.rtnCode := oe;
  310.                         end;
  311.                         status := CS_Searching;
  312.                     end;
  313.                     if oe <> noErr then begin
  314.                         if cacheFaultReturnP <> nil then
  315.                             DisposPtr(ptr(cacheFaultReturnP));
  316.                         DestroyConnection(cp);
  317.                     end;
  318.                 end;
  319.             end;
  320.         end;
  321.         FindAddress := oe;
  322.     end;
  323.  
  324. procedure FindString (hostIP: longInt; var s: str255);
  325.     begin
  326.         TCPAddrToStr(dnrptr, hostIP, s);
  327.     end;
  328.  
  329. function FindName (var cp: connectionIndex; hostIP: longInt; dataptr: univ ptr): OSErr;
  330.     var
  331.         oe: OSErr;
  332.         cpi: connectionIndex;
  333.     begin
  334.         oe := CreateConnection(cp, dataptr);
  335.         if oe = noErr then begin
  336.             cpi := cp;
  337.             if ValidConnection(cpi) then begin
  338.                 with connections[cpi] do begin
  339.                     cacheFaultReturnP := myHostInfoPtr(NewPtr(SizeOf(myHostInfo)));
  340.                     if cacheFaultReturnP = nil then
  341.                         oe := memFullErr
  342.                     else begin
  343.                         cacheFaultReturnP^.done := 0;
  344.                         oe := TCPAddrToName(dnrptr, hostIP, cacheFaultReturnP^.hi, cacheFaultReturnP^.done);
  345.                         if oe = cacheFault then begin
  346.                             timeout := TickCount + TO_FindName;
  347.                             oe := noErr;
  348.                         end
  349.                         else begin
  350.                             cacheFaultReturnP^.done := -1;
  351.                             cacheFaultReturnP^.hi.rtnCode := oe;
  352.                         end;
  353.                         status := CS_NameSearching;
  354.                     end;
  355.                     if oe <> noErr then begin
  356.                         if cacheFaultReturnP <> nil then
  357.                             DisposPtr(ptr(cacheFaultReturnP));
  358.                         DestroyConnection(cp);
  359.                     end;
  360.                 end;
  361.             end;
  362.         end;
  363.         FindName := oe;
  364.     end;
  365.  
  366. function NewPassiveConnection (var cp: connectionIndex; buffersize: longInt; localport: integer; remotehost: longInt; remoteport: integer; dataptr: univ ptr): OSErr;
  367.     var
  368.         oe: OSErr;
  369.         cpi: connectionIndex;
  370.     begin
  371.         oe := CreateConnection(cp, dataptr);
  372.         cpi := cp;
  373.         if ValidConnection(cpi) then
  374.             with connections[cpi] do begin
  375.                 oe := TCPPassiveOpen(tcpc, buffersize, localPort, remotehost, remoteport, nil);
  376.                 timeout := TickCount + TO_PassiveOpen;
  377.                 status := CS_Opening;
  378.                 if oe <> noErr then
  379.                     DestroyConnection(cp);
  380.             end;
  381.         NewPassiveConnection := oe;
  382.     end;
  383.  
  384. function NewActiveConnection (var cp: connectionIndex; buffersize: longInt; remotehost: longInt; remoteport: integer; dataptr: univ ptr): OSErr;
  385.     var
  386.         oe: OSErr;
  387.         cpi: connectionIndex;
  388.     begin
  389.         oe := CreateConnection(cp, dataptr);
  390.         cpi := cp;
  391.         if ValidConnection(cpi) then
  392.             with connections[cpi] do begin
  393.                 oe := TCPActiveOpen(tcpc, buffersize, 0, remotehost, remoteport, nil);
  394.                 timeout := TickCount + TO_ActiveOpen;
  395.                 status := CS_Opening;
  396.                 if oe <> noErr then
  397.                     DestroyConnection(cp);
  398.             end;
  399.         NewActiveConnection := oe;
  400.     end;
  401.  
  402. procedure CloseConnection (cp: connectionIndex);
  403.     var
  404.         oe: OSErr;
  405.     begin
  406.         if ValidConnection(cp) then
  407.             with connections[cp] do begin
  408.                 if not closedone then begin
  409.                     if MyTCPState(tcpc) <> T_Closed then
  410.                         oe := TCPClose(tcpc, nil);
  411.                     closedone := true;
  412.                 end;
  413.                 status := CS_Closing;
  414.             end;
  415.     end;
  416.  
  417. procedure AbortConnection (cp: connectionIndex);
  418.     var
  419.         oe: OSErr;
  420.     begin
  421.         if ValidConnection(cp) then
  422.             with connections[cp] do begin
  423.                 if MyTCPState(tcpc) <> T_Closed then
  424.                     oe := TCPAbort(tcpc);
  425.                 status := CS_Closing;
  426.             end;
  427.     end;
  428.  
  429. function GetConnectionEvent (cp: connectionIndex; var cer: connectionEventRecord): boolean;
  430.     procedure HandleConnection (cp: connectionIndex);
  431.         var
  432.             oe: OSErr;
  433.             dummysp: stringPtr;
  434.             l: integer;
  435.             rcp: connectionIndex;
  436.         begin
  437.             if (cp < 1) or (cp > max_connections) then
  438.                 DebugStr('GetConnectionEvent:Invalid Connection Index');
  439.             if connections[cp].magic <> TCPCMagic then
  440.                 DebugStr('GetConnectionEvent:Bad TCPCMagic number');
  441.             with connections[cp] do begin
  442.                 rcp := conmagic;
  443.                 cer.connection := rcp;
  444.                 cer.tcpc := tcpc;
  445.                 cer.dataptr := dataptr;
  446.                 cer.timedout := false;
  447.                 case status of
  448.                     CS_NameSearching: 
  449.                         with cacheFaultReturnP^, hi do begin
  450.                             if done <> 0 then begin
  451.                                 if rtnCode = noErr then begin
  452.                                     cer.event := C_NameFound;
  453.                                     SanitizeHostName(rtnHostName);
  454.                                     stringHandle(cer.value) := NewString(rtnHostName);
  455.                                 end
  456.                                 else begin
  457.                                     cer.event := C_NameSearchFailed;
  458.                                     cer.value := rtnCode;
  459.                                 end
  460.                             end
  461.                             else if TickCount > timeout then begin
  462.                                 cer.event := C_NameSearchFailed;
  463.                                 cer.value := 1;
  464.                                 cer.timedout := true;
  465.                             end;
  466.                             if cer.event <> C_NoEvent then begin  { Destroy the connection now }
  467.                                 if done <> 0 then  { If we timed out, then we'll just have to abandon this block.  Oh well }
  468.                                     DisposPtr(ptr(cacheFaultReturnP));
  469.                                 cacheFaultReturnP := nil;
  470.                                 DestroyConnection(rcp);
  471.                             end; {if}
  472.                         end; {with}
  473.                     CS_Searching: 
  474.                         with cacheFaultReturnP^, hi do begin
  475.                             if rtnCode = noErr then begin
  476.                                 cer.event := C_Found;
  477.                                 cer.value := addrs[1];
  478.                             end
  479.                             else if done <> 0 then begin
  480.                                 cer.event := C_SearchFailed;
  481.                                 cer.value := rtnCode;
  482.                             end
  483.                             else if TickCount > timeout then begin
  484.                                 cer.event := C_SearchFailed;
  485.                                 cer.value := 1;
  486.                                 cer.timedout := true;
  487.                             end;
  488.                             if cer.event <> C_NoEvent then begin  { Destroy the connection now }
  489.                                 if done <> 0 then  { If we timed out, then we'll just have to abandon this block.  Oh well }
  490.                                     DisposPtr(ptr(cacheFaultReturnP));
  491.                                 cacheFaultReturnP := nil;
  492.                                 DestroyConnection(rcp);
  493.                             end; {if}
  494.                         end; {with}
  495.                     CS_Opening: 
  496.                         case MyTCPState(tcpc) of
  497.                             T_WaitingForOpen, T_Opening, T_Listening: 
  498.                                 if TickCount > timeout then begin
  499.                                     CloseConnection(rcp);
  500.                                     cer.event := C_FailedToOpen;
  501.                                     cer.timedout := true;
  502.                                 end;
  503.                             T_Established: 
  504.                                 begin
  505.                                 cer.event := C_Established;
  506.                                 status := CS_Established;
  507.                                 timeout := maxLongInt;
  508.                             end;
  509.                             T_PleaseClose, T_Closing: 
  510.                                 begin
  511.                                 CloseConnection(rcp);
  512.                                 cer.value := 1;
  513.                                 cer.event := C_FailedToOpen;
  514.                                 timeout := TickCount + TO_Closing;
  515.                             end;
  516.                             T_Closed: 
  517.                                 begin
  518.                                 status := CS_Closing;
  519.                                 cer.value := 2;
  520.                                 cer.event := C_FailedToOpen;
  521.                                 timeout := TickCount + TO_Closing;
  522.                             end;
  523.                             otherwise
  524.                                 ;
  525.                         end; {case }
  526.                     CS_Established: 
  527.                         case MyTCPState(tcpc) of
  528.                             T_WaitingForOpen, T_Opening, T_Listening: 
  529.                                 DebugStr('Strange State 1');
  530.                             T_Established: 
  531.                                 begin
  532.                                 cer.value := TCPCharsAvailable(tcpc);
  533.                                 if cer.value > 0 then
  534.                                     cer.event := C_CharsAvailable;
  535.                             end;
  536.                             T_PleaseClose, T_Closing: 
  537.                                 begin
  538.                                 cer.value := TCPCharsAvailable(tcpc);
  539.                                 if cer.value > 0 then
  540.                                     cer.event := C_CharsAvailable
  541.                                 else begin
  542. {    CloseConnection(rcp);}
  543.                                     status := CS_Closing;
  544.                                     cer.event := C_Closing;
  545.                                     timeout := TickCount + TO_Closing;
  546.                                 end;
  547.                             end;
  548.                             T_Closed: 
  549.                                 begin
  550.                                 status := CS_Closing;
  551.                                 cer.event := C_Closing;
  552.                                 timeout := TickCount + TO_Closing;
  553.                             end;
  554.                             otherwise
  555.                                 ;
  556.                         end;
  557.                     CS_Closing: 
  558.                         case MyTCPState(tcpc) of
  559.                             T_WaitingForOpen, T_Opening, T_Listening: 
  560.                                 DebugStr('Strange State 2');
  561.                             T_PleaseClose, T_Closing, T_Established: 
  562.                                 begin
  563.                                 cer.value := TCPCharsAvailable(tcpc);
  564.                                 if cer.value > 0 then
  565.                                     cer.event := C_CharsAvailable
  566.                                 else if TickCount > timeout then begin
  567.                                     cer.event := C_Closed;
  568.                                     if tcpc <> nil then
  569.                                         oe := TCPRelease(tcpc);
  570.                                     cer.timedout := true;
  571.                                     DestroyConnection(rcp);
  572.                                 end;
  573.                             end;
  574.                             T_Closed: 
  575.                                 begin
  576.                                 cer.event := C_Closed;
  577.                                 if tcpc <> nil then
  578.                                     oe := TCPRelease(tcpc);
  579.                                 DestroyConnection(rcp);
  580.                             end;
  581.                             otherwise
  582.                                 ;
  583.                         end;
  584.                     otherwise
  585.                         ;
  586.                 end;
  587.  
  588.                 if (cer.event = C_NoEvent) & (TickCount > heartbeat) then begin
  589.                     cer.event := C_HeartBeat;
  590.                     heartbeat := TickCount + period;
  591.                 end;
  592.  
  593.             end;{with}
  594.         end;{HandleConnection}
  595.         var
  596.             oci: connectionIndex;
  597.     begin
  598.         cer.event := C_NoEvent;
  599.         if cp <> any_connection then begin
  600.             if ValidConnection(cp) then
  601.                 HandleConnection(cp);
  602.         end
  603.         else begin
  604.             oci := connectionItem;
  605.             repeat
  606.                 if connections[connectionItem].magic = TCPCMagic then begin
  607.                     HandleConnection(connectionItem);
  608.                     if cer.event <> C_NoEvent then
  609.                         leave;
  610.                 end;{if}
  611.                 if connectionItem = max_connections then
  612.                     connectionItem := 1
  613.                 else
  614.                     connectionItem := connectionItem + 1;
  615.             until oci = connectionItem;
  616.         end;{if}
  617.         GetConnectionEvent := cer.event <> C_NoEvent;
  618.     end;{GetConnectionEvent}
  619.  
  620. end.